package com.hzy.fivepalace.wx.service;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.DesensitizedUtil;
import com.hzy.fivepalace.common.type.UserLevelTypeEnums;
import com.hzy.fivepalace.common.type.UserStatusTypeEnums;
import com.hzy.fivepalace.common.type.VipTypeEnums;
import com.hzy.fivepalace.common.util.*;
import com.hzy.fivepalace.db.dao.DtsPointsDetailMapper;
import com.hzy.fivepalace.db.domain.DtsPointsDetail;
import com.hzy.fivepalace.db.domain.DtsUser;
import com.hzy.fivepalace.db.domain.DtsWxConfig;
import com.hzy.fivepalace.db.service.DtsSystemConfigService;
import com.hzy.fivepalace.db.service.DtsUserService;
import com.hzy.fivepalace.db.service.WxConfigService;
import com.hzy.fivepalace.wx.dao.UserToken;
import com.hzy.fivepalace.wx.dao.WxLoginInfo;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录鉴权服务
 */
@Service
public class LoginService {

    private static final Logger logger = LoggerFactory.getLogger(LoginService.class);

    @Autowired
    private DtsUserService userService;

    @Autowired
    private WxMaService wxService;

    @Autowired
    private WxConfigService wxConfigService;


    @Autowired
    private UserTokenManager userTokenManager;

    @Resource
    private Redisson redisson;

    @Autowired
    private DtsSystemConfigService systemConfigService;


    @Resource
    private DtsPointsDetailMapper dtsPointsDetailMapper;

    @Value("${hzy.wx.app-id}")
    private String appId;


    /**
     * 获取微信openid
     *
     * @param code
     * @return
     */
    public Object getOpenId(String code) {
        if (StringUtils.isBlank(code)) {
            return ResponseUtil.fail("授权信息为空");
        }

        String openId = "";
        String sessionKey = "";
        try {
            WxMaJscode2SessionResult result = wxService.switchoverTo(appId).getUserService().getSessionInfo(code);
            openId = result.getOpenid();
            sessionKey = result.getSessionKey();
        } catch (Exception e) {
            logger.error("获取微信openid失败：code:{},msg:{}", code, e.getMessage());
            return ResponseUtil.fail("微信授权失败," + e.getMessage());
        }
        Map result = new HashMap<>();
        result.put("openid", openId);
        result.put("sessionKey", sessionKey);
        return ResponseUtil.ok(result);
    }


    /**
     * 获取测试token
     *
     * @param userId
     * @return
     */
    public Object getTokenTest(Integer userId) {
        DtsUser user = userService.findById(userId);
        if (null == user) {
            return ResponseUtil.fail("用户不存在");
        }
        // token
        UserToken userToken = null;
        try {
            //删除缓存中用户老的token,这样就保证了一个用户只能登录一台设备
            userTokenManager.removeToken(user.getId());
            //生成新的token
            userToken = userTokenManager.generateToken(user.getId(), user.getUsername());
        } catch (Exception e) {
            return ResponseUtil.fail("token生成失败，msg:" + e.getMessage());
        }

        return ResponseUtil.ok(userToken.getToken());
    }

    /**
     * 微信登录
     *
     * @param login
     * @param request
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public Object toWxLogin(WxLoginInfo login, HttpServletRequest request) {
        if (StringUtils.isBlank(login.getOpenid())) {
            return ResponseUtil.fail("参数【openid】为空");
        }
        RLock lock = redisson.getLock("wx_login_" + login.getOpenid());
        if (lock.isLocked()) {
            return ResponseUtil.frequent();
        }
        lock.lock(30, TimeUnit.SECONDS);

        if (StringUtils.isBlank(login.getSessionKey())) {
            lock.unlock();
            return ResponseUtil.fail("参数【sessionKey】为空");
        }

        if (StringUtils.isBlank(login.getEncryptedData())) {
            lock.unlock();
            return ResponseUtil.fail("参数【encryptedData】为空");
        }

        if (StringUtils.isBlank(login.getIv())) {
            lock.unlock();
            return ResponseUtil.fail("参数【iv】为空");
        }

        String phone = "";
        try {
            String result = SecretUtilTools.decrypt(login.getEncryptedData(), login.getSessionKey(), login.getIv(), "UTF-8");
            phone = JacksonUtil.parseString(result, "phoneNumber");
            if (StringUtils.isBlank(result) || StringUtils.isBlank(phone)) {
                logger.error("微信登录,解析手机号为空：openid:{}", login.getOpenid());
                lock.unlock();
                return ResponseUtil.fail("微信授权失败,手机号解析错误");
            }
        } catch (Exception e) {
            logger.error("微信登录,解析手机号错误：openid:{},msg:{}", login.getOpenid(), e);
            lock.unlock();
            return ResponseUtil.fail("微信授权失败,手机号解析异常");
        }

        String nickName = (StringUtils.isBlank(login.getNickName()) || StringUtils.equals("微信用户", login.getNickName())) ? null : login.getNickName();
        Integer gender = null == login.getGender() ? 0 : login.getGender();

        Map<Object, Object> result = new HashMap<Object, Object>();
        //根据手机号查询用户
        DtsUser user = userService.queryByPhone(phone);
        if (null == user) {//未注册进行注册
            //对传入的用户信息进行处理
            String avatarUrl = StringUtils.isBlank(login.getAvatarUrl()) ? null : login.getAvatarUrl();
            //随机获取一个头像
            String randomAvatar = systemConfigService.getRandomAvatar();
            if(!StringUtils.isBlank(randomAvatar)){
                avatarUrl=randomAvatar;
            }
            //判断传入的用户昵称是否获取到了,未获取到就用脱敏后的手机号为用户昵称
            if (StringUtils.isBlank(nickName) || StringUtils.equals("微信用户", nickName)) {
                nickName = DesensitizedUtil.mobilePhone(phone);
            }
            user = new DtsUser();
            user.setUsername(nickName);
            user.setWeixinOpenid(login.getOpenid());
            user.setAvatar(avatarUrl);
            user.setNickname(nickName);
            if (null != gender) {
                user.setGender(gender.byteValue());
            }
            user.setUserLevel(UserLevelTypeEnums.USER.getId());
            user.setStatus(UserStatusTypeEnums.USABLE.getId());
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.getRealIp(request));
            user.setMobile(phone);
            userService.add(user);
            //生成用户推荐码
            String recode = ShareCodeUtil.toSerialCode(user.getId(), 7);
            user.setRecodeCode(recode);
            userService.updateById(user);
        } else {//用户存在去判断账号状态并更新信息
            //账号状态判断
            if (user.getDeleted()) {
                lock.unlock();
                return ResponseUtil.fail("登录失败,账号已被删除");
            }
            if (UserStatusTypeEnums.DISABLE.getId().equals(user.getStatus())) {
                lock.unlock();
                return ResponseUtil.fail("登录失败,账号已被禁用");
            }
            if (UserStatusTypeEnums.CANCEL.getId().equals(user.getStatus())) {
                lock.unlock();
                return ResponseUtil.fail("登录失败,账号已注销");
            }
            if (null != gender) {
                user.setGender(gender.byteValue());
            }
            user.setUsername(nickName);
            user.setNickname(nickName);
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.getRealIp(request));
            user.setWeixinOpenid(login.getOpenid());
            userService.updateById(user);
        }

        // token
        UserToken userToken = null;
        try {
            //删除缓存中用户老的token,这样就保证了一个用户只能登录一台设备
            userTokenManager.removeToken(user.getId());
            //生成新token
            userToken = userTokenManager.generateToken(user.getId(), login.getSessionKey());
        } catch (Exception e) {
            logger.error("微信登录失败,生成token失败：userId:{},msg:{}", user.getId(), e.getMessage());
            lock.unlock();
            return ResponseUtil.fail("token生成失败");
        }

        if(!StringUtils.isBlank(login.getRecodeCode())){//推荐码不为空
            if(null==user.getRecodeUserId()||user.getRecodeUserId().equals(0)){//并且当前用户没有绑定推荐人查询推荐用户信息
                DtsUser reUser=userService.queryByRecodeCode(login.getRecodeCode());
                if(null!=reUser&&!reUser.getId().equals(user.getId())){
                    DtsUser userUpd=new DtsUser();
                    userUpd.setId(user.getId());
                    userUpd.setRecodeUserId(reUser.getId());
                    userUpd.setRecodeBindTime(LocalDateTime.now());
                    userService.updateById(userUpd);
                    //获取微信配置
                    DtsWxConfig wxConfig=wxConfigService.getWxConfig();
                    //判断推荐用户的会员类型
                    if(null==VipTypeEnums.getEnum(reUser.getVipType())){//普通用户那就得积分
                        if(null!=wxConfig&&null!=wxConfig.getExtendPoints()&&wxConfig.getExtendPoints().compareTo(new BigDecimal("0"))>0){
                            DtsPointsDetail pointsDetail=new DtsPointsDetail();
                            pointsDetail.setUserId(reUser.getId());
                            pointsDetail.setToUserId(user.getId());
                            pointsDetail.setAddTime(LocalDateTime.now());
                            pointsDetail.setPoints(wxConfig.getExtendPoints());
                            pointsDetail.setParticularsMatter("推广分享");
                            dtsPointsDetailMapper.insertSelective(pointsDetail);
                        }
                    }
                }

            }
        }

        result.put("token", userToken.getToken());
        result.put("nickName", user.getNickname());
        result.put("avatar", user.getAvatar());
        result.put("recodeCode", user.getRecodeCode());
        lock.unlock();
        return ResponseUtil.ok("登录成功", result);
    }

    /**
     * 退出登录
     *
     * @param userId
     * @return
     */
    public Object toLogout(Integer userId) {
        if (userId == null) {
            return ResponseUtil.ok("退出成功", null);
        }
        RLock lock = redisson.getLock("wx_toLogout_" + userId);
        if (lock.isLocked()) {
            return ResponseUtil.frequent();
        }
        lock.lock(30, TimeUnit.SECONDS);
        try {
            userTokenManager.removeToken(userId);
        } catch (Exception e) {
            logger.error("退出登录出错：userId:{},msg:{}", userId, e.getMessage());
            lock.unlock();
            return ResponseUtil.fail("退出登录异常");
        }
        //移除锁
        lock.unlock();
        return ResponseUtil.ok("退出成功", null);
    }

}
